package cn.ibizlab.util.adapter.util.helper;

import cn.ibizlab.util.adapter.service.SysRuntimeModelService;
import cn.ibizlab.util.domain.IEntity;
import cn.ibizlab.util.filter.FilterBase;
import cn.ibizlab.util.filter.SearchCondition;
import cn.ibizlab.util.helper.BeanCache;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import net.ibizsys.central.util.EntityDTO;
import net.ibizsys.central.util.IEntityDTO;
import net.ibizsys.central.util.ISearchContext;
import net.ibizsys.runtime.util.*;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.regex.Pattern;

import static cn.ibizlab.util.adapter.util.constant.DELogicConstant.PARAM_DATAENTITY;

public class CachedBeanCopier {

    private CachedBeanCopier() {
        throw new IllegalStateException("Utility class");
    }

    public static void copy(Object srcObj, Object destObj) {
        copy(srcObj, destObj, true);
    }

    public static void copy(Object srcObj, Object destObj, boolean bIncEmpty) {
        if (srcObj == null || destObj == null) {
            return;
        } else if (srcObj instanceof IEntity && destObj instanceof IEntityDTO) {
            BeanCache.get(srcObj.getClass()).getFields().forEach(item -> {
                Object value = ((IEntity) srcObj).get(item.getCodeName());
                if (!ObjectUtils.isEmpty(value) || ObjectUtils.isEmpty(value) && ((IEntity) srcObj).getFocusNull().contains(item.getJsonName()) && bIncEmpty) {
                    ((IEntityDTO) destObj).set(item.getCodeName(), value);
                }
            });
            ((IEntity) srcObj).getExtensionparams().entrySet().forEach(entry -> {
                Object value = entry.getValue();
                if (!ObjectUtils.isEmpty(value) || ObjectUtils.isEmpty(value) && bIncEmpty) {
                    ((IEntityDTO) destObj).set(entry.getKey(), value);
                }
            });
            return;
        } else if (srcObj instanceof IEntityDTO && destObj instanceof IEntity) {
            for (Map.Entry<String, Object> entry : ((IEntityDTO) srcObj).any().entrySet()) {
                ((IEntity) destObj).set(entry.getKey(), entry.getValue());
            }
            return;
        }
        BeanUtils.copyProperties(srcObj, destObj);
    }

    /**
     * entity -> entityDto
     * @param entity
     * @param entityDto
     * @return
     */
    public static IEntityDTO copyEntity2Dto(IEntity entity, IEntityDTO entityDto) {

        BeanCache.BeanSchema entitySchema = SysRuntimeModelService.getDataEntityUtil().getEntitySchema(entity);
        //实体属性
        for (BeanCache.FieldItem field : entitySchema.getFields()) {
            String fieldName = !ObjectUtils.isEmpty(field.getJsonName())? field.getJsonName() : field.getCodeName();
            Object fieldValue = entity.get(fieldName);

            //空值检查
            if (fieldValue == null && !entity.isFocusNull(fieldName))
                continue;

            if (fieldValue instanceof List) {
                List params = new ArrayList<>();
                for (Object param : (List) fieldValue) {
                    if (param instanceof Map) {
                        IEntityDTO entityDTO = getEntityDto((Map) param);
                        if (entityDTO != null)
                            params.add(entityDTO);
                    } else if (param instanceof IEntity) {
                        IEntityDTO entityDTO = SysRuntimeModelService.getDataEntityUtil().createEmptyEntityDto((IEntity) param);
                        copyEntity2Dto((IEntity) param, entityDTO);
                        params.add(entityDTO);
                    } else
                        params.add(param);
                }
                fieldValue = params;
            } else if (fieldValue instanceof IEntity) {
                IEntityDTO entityDTO = SysRuntimeModelService.getDataEntityUtil().createEmptyEntityDto((IEntity) fieldValue);
                copyEntity2Dto((IEntity) fieldValue, entityDTO);
                fieldValue = entityDTO;
            } else if (fieldValue instanceof Map) {
                IEntityDTO entityDTO = getEntityDto((Map) fieldValue);
                if (entityDTO != null)
                    fieldValue = entityDTO;
            }
            entityDto.set(fieldName, fieldValue);
        }
        //扩展属性
        if (!ObjectUtils.isEmpty(entity.getExtensionparams())) {
            for (Map.Entry<String, Object> entry : entity.getExtensionparams().entrySet()) {
                entityDto.set(entry.getKey(), entry.getValue());
            }
        }
        //entityDto中存储entity原始对象
        if(!cn.ibizlab.util.domain.EntityBase.class.getSimpleName().equalsIgnoreCase(entity.getClass().getSimpleName()))
            entityDto.set(PARAM_DATAENTITY, entity);
        return entityDto;
    }

    /**
     * entity -> entityDto
     *
     * @param entities
     * @param entityDTOS
     * @return
     */
    public static List<IEntityDTO> copyEntity2Dto(List<IEntity> entities, List<IEntityDTO> entityDTOS) {
        for (IEntity entity : entities) {
            IEntityDTO dto = SysRuntimeModelService.getDataEntityUtil().createEmptyEntityDto(entity);
            entityDTOS.add(copyEntity2Dto(entity, dto));
        }
        return entityDTOS;
    }

    /**
     * map -> entityDto
     *
     * @param map
     * @return
     */
    private static IEntityDTO getEntityDto(Map<String, Object> map) {

        if (map == null)
            return null;

        IEntityDTO entityDTO = new EntityDTO();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            entityDTO.set(entry.getKey(), entry.getValue());
        }

        return entityDTO;
    }

    /**
     * entityDto -> entity
     *
     * @param entityDto
     * @param entity
     * @return
     */
    public static IEntity copyEntityDto2Entity(IEntityDTO entityDto, IEntity entity) {

        Map<String, Object> entityMap = getEntityMap(entityDto);
        if(!ObjectUtils.isEmpty(entityMap)){
            for(Map.Entry<String,Object> entry : entityMap.entrySet()){
                entity.set(entry.getKey(), entry.getValue());
            }
        }
        return entity;
    }

    public static IEntity copyEntityDto2Entity(Entity entityDto, IEntity entity) {

        if(!ObjectUtils.isEmpty(entityDto.any())){
            for(Map.Entry<String,Object> entry : entityDto.any().entrySet()){
                entity.set(entry.getKey(),entry.getValue());
            }
        }
        return entity;
    }


    /**
     * entity -> entity
     * @param entity
     * @param entity2
     * @return
     */
    public static IEntity copyIEntity2Entity(net.ibizsys.runtime.util.IEntity entity, IEntity entity2) {
        Map<String, Object> entityMap = getEntityMap(entity);
        if (!ObjectUtils.isEmpty(entityMap)) {
            for (Map.Entry<String, Object> entry : entityMap.entrySet()) {
                entity2.set(entry.getKey(), entry.getValue());
            }
        }
        return entity2;
    }

    /**
     * entityDto -> map
     *
     * @param entityDto
     * @return
     */
    protected static Map<String, Object> getEntityMap(net.ibizsys.runtime.util.IEntity entityDto) {

        Map<String, Object> entity = new HashMap();
        if (entityDto == null || ObjectUtils.isEmpty(entityDto.any()))
            return entity;

        for (Map.Entry<String, Object> entry : entityDto.any().entrySet()) {

            String paramKey = entry.getKey();
            Object paramValue = entry.getValue();

            //忽略预置属性
            if(PARAM_DATAENTITY.equals(paramKey))
                continue;

            if (paramValue != null && paramValue instanceof IEntityDTO) {
                paramValue = getEntityMap((IEntityDTO) paramValue);
            } else if (paramValue != null && paramValue instanceof List) {
                List params = new ArrayList();
                for (Object param : (List) paramValue) {
                    //dto存在原始类型，则使用原始类型回调，不存在原始类型，则使用map回调
                    if (param instanceof IEntityDTO) {
                        IEntityDTO paramDto = (IEntityDTO) param;
                        if(paramDto.get(PARAM_DATAENTITY) != null && paramDto.get(PARAM_DATAENTITY) instanceof IEntity){
                            IEntity paramEntity = (IEntity) paramDto.get(PARAM_DATAENTITY);
                            copyEntityDto2Entity(paramDto,paramEntity);
                            params.add(paramEntity);
                        }
                        else{
                            Map entityMap = getEntityMap((IEntityDTO) param);
                            if (entityMap != null)
                                params.add(entityMap);
                        }
                    } else if (param instanceof net.ibizsys.runtime.util.IEntity
                            && ((net.ibizsys.runtime.util.IEntity) param).get(PARAM_DATAENTITY) != null
                            && ((net.ibizsys.runtime.util.IEntity) param).get(PARAM_DATAENTITY) instanceof IEntity) {
                        //处理逻辑CloneParam时，类型为IEntity
                        IEntity paramEntity = (IEntity) ((net.ibizsys.runtime.util.IEntity) param).get(PARAM_DATAENTITY);
                        copyIEntity2Entity((net.ibizsys.runtime.util.IEntity) param, paramEntity);
                        params.add(paramEntity);
                    }
                    else
                        params.add(param);
                }
                paramValue = params;
            }
            entity.put(paramKey, paramValue);
        }

        return entity;
    }

    private static Pattern in_pattern = Pattern.compile("n_.*_in");

    /**
     * filterDto -> filter
     *
     * @param filterDto
     * @param filter
     * @return
     */
    public static FilterBase copyFilterDto2Entity(ISearchContext filterDto, FilterBase filter) {
        //扩展参数
        Map<String, Object> params = filterDto.any();
        if (!ObjectUtils.isEmpty(params)) {
            for (Map.Entry<String, Object> param : params.entrySet()) {
                String name = param.getKey();
                Object value = param.getValue();
                //in参数转string
                if(in_pattern.matcher(name).matches() && !ObjectUtils.isEmpty(value)){
                    if(value instanceof Map)
                        value = String.join(",",((Map)value).values());
                    else if(value instanceof Set)
                        value = String.join(",",((Set)value));
                }
                filter.set(name,value);
            }
        }
        //分页
        Pageable page = filterDto.getPageable();
        if (page != null) {
            filter.setPage(page.getPageNumber());
            filter.setSize(page.getPageSize());
        }
        //自定义条件
        if (!ObjectUtils.isEmpty(filterDto.getSearchConds())) {
            String conditions = getCustomConditions(filterDto,filter);
            if (!ObjectUtils.isEmpty(conditions)) {
                filter.setCustomCond(conditions);
            }
        }
        //自定义条件
        if (ObjectUtils.isEmpty(filter.getCustomCond()) && !ObjectUtils.isEmpty(filterDto.getSearchConds())) {
            List<SearchCondition> searchConditions = JSONArray.parseArray(JSON.toJSONString(filterDto.getSearchConds()), SearchCondition.class);
            for(SearchCondition searchCondition : searchConditions){
                parseFilterParams(searchCondition,filter.getParams());
            }
            filter.setSearchConditions(searchConditions);
        }

        //排序
        Sort sort = filterDto.getPageSort();
        if (sort != null && sort != Sort.unsorted()) {
            filter.setSort(sort.toString().replace(":", ",").replace(" ", ""));
        }
        return filter;
    }

    /**
     * 获取自定义条件
     *
     * @param filterDto
     * @param filter
     * @return
     */
    private static String getCustomConditions(ISearchContext filterDto, FilterBase filter) {
        String strCondition = null;
        for (ISearchCond searchCond : filterDto.getSearchConds()) {
            String condition = getCondition(searchCond);
            if (!ObjectUtils.isEmpty(condition)) {
                if (!ObjectUtils.isEmpty(strCondition))
                    strCondition = String.format("%1$s AND %2$s ", strCondition, condition);
                else
                    strCondition = condition;
            }
            //空值条件
            if (searchCond instanceof ISearchFieldCond &&
                    (Conditions.ISNULL.equals(((ISearchFieldCond) searchCond).getCondOp()) ||
                            Conditions.ISNOTNULL.equals(((ISearchFieldCond) searchCond).getCondOp()))) {
                ISearchFieldCond searchFieldCond = (ISearchFieldCond) searchCond;
                filter.set(String.format("n_%1$s_%2$s", searchFieldCond.getFieldName(), searchFieldCond.getCondOp()).toLowerCase(), "");
            }
        }
        return strCondition;
    }

    /**
     * 获取自定义条件
     *
     * @param cond
     * @return
     */
    private static String getCondition(ISearchCond cond) {
        String strCondition = null;
        if (cond instanceof net.ibizsys.runtime.util.ISearchGroupCond) {
            net.ibizsys.runtime.util.ISearchGroupCond searchGroupCond = (net.ibizsys.runtime.util.ISearchGroupCond) cond;
            List<ISearchCond> childConditions = searchGroupCond.getSearchCondsIf();
            if (!ObjectUtils.isEmpty(childConditions)) {
                for (ISearchCond childCondition : childConditions) {
                    String strChildCondition = getCondition(childCondition);
                    if (!ObjectUtils.isEmpty(strChildCondition)) {
                        if (!ObjectUtils.isEmpty(strCondition))
                            strCondition = String.format("%1$s %2$s %3$s", strCondition, searchGroupCond.getCondOp(), strChildCondition);
                        else
                            strCondition = strChildCondition;
                    }
                }
                if (!ObjectUtils.isEmpty(strCondition)) {
                    strCondition = String.format("(%1$s)", strCondition);
                }
            }
        } else if (cond instanceof ISearchCustomCond) {
            strCondition = ((ISearchCustomCond) cond).getCustomCond();
        }
        return strCondition;
    }

    /**
     * 自定义条件参数处理
     * @param searchCondition
     * @param contextParams
     */
    public static void parseFilterParams(SearchCondition searchCondition , Map<String, Object> contextParams){
       if(!ObjectUtils.isEmpty(searchCondition) && !ObjectUtils.isEmpty(contextParams)){
           Object value = searchCondition.getValue();
           //将value = n_xx参数替换为具体属性值
           if(searchCondition.isParamMode() && !ObjectUtils.isEmpty(value) && contextParams.containsKey(value.toString())){
               searchCondition.setValue(contextParams.get(value.toString()));
           }
           if(!ObjectUtils.isEmpty(searchCondition.getSearchConds())){
               searchCondition.getSearchConds().forEach(e-> parseFilterParams(e,contextParams));
           }
       }
    }

}